﻿/*
array 是固定大小的顺序容器。
在内部，一个数组除了它包含的元素以外不保存任何数据。存储大小和[]声明的普通数据一样高效。这个类只是增加了一层成员函数和全局函数。
和其它标准容器不同，数组具有固定的大小，并且不通过分配器管理其元素的分配。
零大小的数组是有效的，但是它们不应该被解除引用。
数组容器的另一个独特特性是它们可以被当做元组对象来处理：使用get函数来访问数组元素，就相当于它是一个元组，以及专门的tuple_size 和 tuple_element 类型。

template<class T, size_t N> class array;
*/
#include <iostream>
#include <array>
#include <ctime>
//#include <cstdlib>
#include <algorithm>

//返回指向数组容器中第一个元素的迭代器
void test_begin()
{
	std::array<int, 5> arr = {2, 16, 77, 34, 50};
	std::cout << "arr contains:";
	for (auto it = arr.begin(); it != arr.end(); it++)
	{
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//返回指向数组容器中最后一个元素之后的理论元素的迭代器
void test_end()
{
	std::array<int, 6> arr = {0};
	int i = 5;
	for (auto it = arr.begin(); it != arr.end(); it++) {
		*it = i++;
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//返回指向数组容器中最后一个元素的反向迭代器
void test_rbegin()
{
	std::array<int, 6> arr = { 5, 6, 7, 8, 9, 10 };
	for (auto it = arr.rbegin(); it != arr.rend(); it++) {
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//返回一个反向迭代器，指向数组中第一个元素之前的理论元素（这被认为是它的反向结束）
void test_rend()
{
	std::array<int, 6> arr = { 0 };
	int i = 0;
	for (auto it = arr.rbegin(); it != arr.rend(); it++) {
		*it = i--;
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//返回指向数组容器中第一个元素的常量迭代器；这个迭代器可以增加和减少，但是不能用来修改它指向的内容
void test_cbegin()
{
	std::array<int, 4> arr = {2, 4, 6, 8};
	std::cout << "arr contains:";
	for (auto it = arr.cbegin(); it != arr.end(); ++it) {
		std::cout << ' ' << *it;
	}
	std::cout << "\n";
}

//返回指向数组容器中最后一个元素之后的理论元素的常量迭代器。这个迭代器可以增加和减少，但是不能用来修改它指向的内容
void test_cend()
{
	std::array<int, 5> arr = {11, 22, 33, 44, 55};

	std::cout << "arr contains:";
	for (auto it = arr.rbegin(); it != arr.rend(); it++) {
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//返回指向数组容器中最后一个元素的常量反向迭代器
void test_crbegin()
{
	std::array<int, 5> arr = {1, 3, 5, 7, 9};
	std::cout << "arr contains:";
	for (auto it = arr.crbegin(); it != arr.crend(); it++) {
		std::cout  << ' ' << *it;
	}

	std::cout << "\n";
}

//返回指向数组容器中第一个元素之前的常量反向迭代器，它被认为是其反向结束
void test_crend()
{
	std::array<double, 5> arr = { 1.1, 4.1, 8.1, 9.1, 10.1 };
	std::cout << "arr contains";
	for (auto it = arr.crbegin(); it != arr.crend(); it++) {
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//返回数组容器中元素的数量
void test_size()
{
	std::array<int, 6> myInts ;//如果没有初始化，容器内部的元素值未知
	std::cout << "size of myInts:" << myInts.size() << std::endl;
	std::cout << "sizeof(myInsts):" << sizeof(myInts) << std::endl;
	for (auto it = myInts.begin(); it != myInts.end(); it++) {
		std::cout << ' ' << *it;
	}

	std::cout << "\n";
}

//max_size： 返回数组容器可容纳的最大元素数。数组对象的max_size 与其 size 一样，始终等于用于实例化数组模板类的第二个模板参数
void test_max_size()
{
	std::array<int, 10> myInts;
	std::cout << "size:" << myInts.size() << std::endl;
	std::cout << "max_size :" << myInts.max_size() << std::endl;
}

//empty： 返回一个布尔值，指示数组容器是否为空，即它的size() 是否为0
void test_empty()
{
	std::array<int, 0> frist;
	std::array<int, 10> second;
	std::cout << "frist array  " << (frist.empty() ? "is empty" : "is not empty") << "\n";
	std::cout << "second array " << (second.empty() ? "is empty" : "is not empty") << "\n";
}

//operator[] 返回数组中第n个位置的元素的引用。与 at() 相似，但 at 会检查数组边界并通过抛出一个 out_of_range 异常来判断 n 是否超出范围，而 operator[] 不检查边界

void test_operator ()
{
	std::array<int, 5> arr = {1, 3, 5, 7, 9};
	for (size_t i = 0; i < arr.size(); i++) {
		std::cout << ' '  << arr[i] ;
	}

	std::cout << "\n";
}

//at： 返回数组中第 n 个位置的元素的引用。与 operator[] 相似，但 at 会检查数组边界并抛出一个 out_of_range 异常来判断 n 是否超出范围，而 opeartor[] 不检查边界
void test_at()
{
	std::array<int, 5> arr;
	for (size_t i = 0; i < arr.size(); i++)
	{
		arr[i] = i;
	}

	for (size_t i = 0; i < arr.size(); i++)
	{
		std::cout << ' ' << arr.at(i);
	}

	std::cout << "\n";
}

//front： 返回对数组容器中第一个元素的引用。begin 返回的是迭代器，front 返回的是直接引用。在空容器中调用此函数会导致未定义的行为
void test_front()
{
	std::array<int, 5> arr = {1, 100, 10000};

	for (size_t i = 0; i < arr.size(); i++)
	{
		std::cout << ' ' << arr.at(i);
	}

	std::cout << "\n";

	arr.front() = -100;
	std::cout << arr.front() << "\n";
	std::cout << arr.back() << "\n";


	for (int &var : arr) {
		std::cout << ' ' << var;
	}

	std::cout << "\n";

}

//back： 返回对数组容器中最后一个元素的引用。end 返回的是迭代器，back 返回的是直接引用。在空容器上调用此函数会导致未定义的行为
void test_back()
{
	std::array<int, 5> arr = { 1, 4, 22, 33,44 };
	for (int& var : arr) std::cout  << ' '<< var;
	std::cout << "\n";
	arr.front() = 100;
	arr.back() = 200;
	std::cout << arr.front() << "\n";
	std::cout << arr.back() << "\n";
}

void test_data()
{
	const char* cstr = "test\0 stri   ng";
	std::array<char, 12> chArr;

	std::memcpy(chArr.data(), cstr, 12);

	std::cout << chArr.data() << "\n";//cout遇到 \0 就停止输出
}

//fill： 用 val 填充数组中所有的元素，将 val 设置为数组对象中所有元素的值

void test_fill()
{
	std::array<int, 10> arr = { 1,2,3 };
	for (int & var : arr) std::cout << ' ' << var;
	std::cout << "\n";
	arr.fill(1024);
	for (int & var : arr) std::cout << ' ' << var;
	std::cout << "\n";
}

//swap:通过 arg 的内容交换数组的内容，这是另一个相同类型的数组对象（包括相同的大小）。与其它容器的交换函数不同，此成员函数通过在各个元素之间执行与其大小相同的单独交换操作，以线性时间运行。
void test_swap()
{
	std::array<int, 5> frist = { 1,3, 5, 7, 9 };
	std::array<int, 5> second = { 2,4,6,8,10 };

	frist.swap(second);

	for (int&var : frist) std::cout << ' ' << var;
	std::cout << "\n";
	for (int&var : second) std::cout << ' ' << var;
	std::cout << "\n";
}

//std::get<0>(myArray); get :传入一个数组容器，返回指定位置元素的引用

void test_get()
{
	std::array<int, 5> arr = { 11,22,33,44,55 };
	std::cout << std::get<0>(arr) << "\n";
}

void test_get2()
{
	std::array<int, 3> myarray = { 10, 20, 30 };
	std::tuple<int, int, int> mytuple(10, 20, 30);

	//std::tuple_element<0, decltype(myarray)>::type myelement;  这句话干了啥

	int myelement = std::get<2>(myarray);
	std::get<2>(myarray) = std::get<0>(myarray);
	std::get<0>(myarray) = myelement;

	std::cout << "firist element in myarray:" << std::get<0>(myarray) << "\n";
	std::cout << "frist element in mytuple:" << std::get<0>(mytuple) << "\n";
}

//relational operator(array) :依次比较数组每个元素的大小关系

void test_realtion_operator()
{
	std::array<int, 5> a = {10, 20, 30, 40, 50};
	std::array<int, 5> b = {10, 20, 30, 40, 50};
	std::array<int, 5> c = {50, 40, 30, 20, 10};

	if (a == b) std::cout << "a and b are equal \n";
	if (a != c) std::cout << "a and c are not equal\n";
	if (b < c) std::cout << "b is less than c\n";
	if (c > b) std::cout << "c is greator than b\n";
	if (a <= b) std::cout << "a is less than or equal to b\n";
	if (a >= b) std::cout << "a is greater than or equal to b\n";
}

using std::cout;
using std::string;
using std::array;
using std::endl;

const int ASIZE = 500000;
long get_a_target_long()
{
	long target = 0;
	cout << "target (0~" << RAND_MAX << "):";
	std::cin >> target;
	return target;
}

string get_a_target_string()
{
	long target = 0;
	char buf[10];

	cout << "target (0~" << RAND_MAX << "):";
	std::cin >> target;
	snprintf(buf, 10, "%d", target);

	return string(buf);

}

int compareLongs(const void* a, const void *b)
{
	return (*(long*)a - *(long*)b);
}

int compareStrings(const void * a, const void * b)
{
	if (*(string*)a > *(string*)b)
		return 1;
	else if (*(string*)a < *(string*)b)
		return -1;
	else
		return 0;
}

void test_array()
{
	cout << "\t test_array()...." << '\n';
array<long, ASIZE> c;

clock_t timeStart = clock();
	for (long i = 0; i < ASIZE; i++) {
		c[i] = rand();
	}

	cout << "milli-seconds : " << (clock() - timeStart) << endl;
	cout << "array.size()= " << c.size() << endl;
	cout << "array.front()= " << c.front() << endl;
	cout << "array.back()= " << c.back() << endl;
	cout << "array.data()= " << c.data() << endl;
	

long target = get_a_target_long();
	timeStart = clock();
	auto it = std::find(c.begin(), c.end(), target);
	cout << "found ," << *it << endl;
	cout << "find milli-seconds : " << clock() - timeStart << endl;



	timeStart = clock();
	qsort(c.data(), ASIZE, sizeof(long), compareLongs);//quack sort 快速排序


	cout << "qsort() + bsearch() , milli-seconds：" << (clock() - timeStart) << endl;
long* pItem = (long*)bsearch(&target, (c.data()), ASIZE, sizeof(long), compareLongs);//二分查找
	if (pItem != NULL)
		cout << "found, " << *pItem << endl;
	else
		cout << "not found!" << endl;
}

int main()
{
	//test_begin();
	//test_end();
	//test_rbegin();
	//test_rend();
	//test_cbegin();
	//test_cend();
	//test_crbegin();
	//test_crend();
	//test_size();
	//test_max_size();
	//test_empty();
	//test_operator();
	//test_at();
	//test_front();
	//test_back();
	//test_data();
	//test_fill();
	//test_swap();
	//test_get2();
	//test_realtion_operator();

	test_array();
	return 0;
}